package com.robmayhew.jsc.ant;

import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.types.FileSet;
import com.robmayhew.jsc.*;

import java.io.*;
import java.util.Vector;
import java.util.Enumeration;


public class SpellTask extends MatchingTask
{
    private String min = "3";
    private String max = "80";
    private File dictionary;
    private File outputFile;
    private File baseDir;
    private boolean buildDictionary = false;
    private boolean dumpWord = false;
    private int allowed = 4;
    private Vector filesets = new Vector();



    private FileUtils fileUtils = FileUtils.newFileUtils();

    /**
     * The name/location of where to create the .cab file.
     */


    /**
     * Base directory to look in for files to CAB.
     */
    public void setBasedir(File baseDir) {
        this.baseDir = baseDir;
    }


    public void setBuildDictionary(boolean b){
        this.buildDictionary = b;
    }
    
    public void setDumpWord(boolean b){
        this.dumpWord = b;
    }
    
    public void setAllowed(int i){
        allowed = i;
    }


    /**
     * Adds a set of files to archive.
     */
    public void addFileset(FileSet set) {
        filesets.addElement(set);
    }

    /*
     * I'm not fond of this pattern: "sub-method expected to throw
     * task-canceling exceptions".  It feels too much like programming
     * for side-effects to me...
     */
    protected void checkConfiguration() throws BuildException {
        if (baseDir == null && filesets.size() == 0) {
            throw new BuildException("basedir attribute or at least one "
                                     + "nested fileset is required!",
                                     getLocation());
        }
        if (baseDir != null && !baseDir.exists()) {
            throw new BuildException("basedir does not exist!", getLocation());
        }

    }




    /**
     * Creates a list file.  This temporary file contains a list of all files
     * to be included in the cab, one file per line.
     *
     * <p>This method expects to only be called on Windows and thus
     * quotes the file names.</p>
     */
    protected File createListFile(Vector files)
        throws IOException {
        File listFile = fileUtils.createTempFile("ant", "", null);
        listFile.deleteOnExit();

        PrintWriter writer = new PrintWriter(new FileOutputStream(listFile));

        int size = files.size();
        for (int i = 0; i < size; i++) {
            writer.println('\"' + files.elementAt(i).toString() + '\"');
        }
        writer.close();

        return listFile;
    }

    /**
     * Append all files found by a directory scanner to a vector.
     */
    protected void appendFiles(Vector files, DirectoryScanner ds, File dir) {
        String[] dsFiles = ds.getIncludedFiles();

        for (int i = 0; i < dsFiles.length; i++) {
            //log(dsFiles[i]);
            files.addElement(dir.getAbsolutePath() + File.separator + dsFiles[i]);
        }
    }

    /**
     * Get the complete list of files to be included in the cab.  Filenames
     * are gathered from filesets if any have been added, otherwise from the
     * traditional include parameters.
     */
    protected Vector getFileList() throws BuildException {
        Vector files = new Vector();

        if (baseDir != null) {
            // get files from old methods - includes and nested include
            appendFiles(files, super.getDirectoryScanner(baseDir), baseDir);
        }

        // get files from filesets
        for (int i = 0; i < filesets.size(); i++) {
            FileSet fs = (FileSet) filesets.elementAt(i);

            if (fs != null) {
                appendFiles(files, fs.getDirectoryScanner(getProject()), fs.getDir(getProject()));
            }
        }

        return files;
    }



    public void setMin(String min)
    {
        this.min = min;
    }

    public void setMax(String max)
    {
        this.max = max;
    }

    public void setDictionary(File dictionary)
    {
        this.dictionary = dictionary;
    }

    public void setBaseDir(File baseDir)
    {
        this.baseDir = baseDir;
    }

    public void setOutputFile(File outputFile)
    {
        this.outputFile = outputFile;
    }

    public void execute() throws BuildException
    {
        try{
            checkConfiguration();

            Vector files = getFileList();




            Enumeration fileEnum = files.elements();


            int min = Integer.parseInt(this.min);
            int max = Integer.parseInt(this.max);
            
            
            GSettings.initialize();
            GSettings.getInstance().ignoreWordSize = min;
            GSettings.getInstance().ignoreWordOverSize = max;
            Project project = new Project();
            log("Building Dictionary");
            if(dictionary != null && dictionary.exists() == false){
                if(dictionary.createNewFile() == false){
                    throw new BuildException("Could not create project dictionary file");
                }
            }else{
                if(dictionary != null && dictionary.isDirectory()){

                    throw new BuildException("Specified dictionary is a directory.");
                }
            }
            if (dictionary != null && !buildDictionary)
            {
                project.setDictionary(dictionary.getPath());
            }
            Scan scan = new Scan(project);
            CheckFiles checker = new CheckFiles();
            log("Checking Files");
            File root = getProject().getBaseDir();
            while(fileEnum.hasMoreElements())
            {

                Object o = fileEnum.nextElement();
                //log(o.getClass().getName());
                String name =  o.toString();

                //log("Checking [" + name + "]");
                checker.checkFile(new File(name), scan, !buildDictionary);
            }
            scan.iterate();
            try
            {
                if(buildDictionary )
                    outputFile = dictionary;
                PrintWriter pw = new PrintWriter(new FileWriter(outputFile, buildDictionary));
                if(scan.size() != 0 && !buildDictionary ){
                    pw.println("Found " + scan.size() + " words");
                    log(scan.size() + " words not in dictionary");
                }else{
                    log("No misspellings found");
                }
                for (int i = 0; i < scan.size(); i++)
                {
                    Miss miss = scan.get(i);
                    if(buildDictionary ){
                        if(miss.size() > allowed)
                            pw.println(miss.getWord());
                        //else
                        //    log("Will check for [" + miss.getWord() + "] Found [" + miss.size() + "]");
                    }
                    else
                    {
                        pw.println(miss.getWord() );
                        if(!dumpWord){
                            for (int j = 0; j < miss.size(); j++)
                            {
                                Occurrence occ = miss.get(j);
                            
                                pw.println("       File:" + occ.getFile() + " Line: " + occ.getLine());
                            
                                
                                //pw.println("     [" + occ.getLine().trim() + "]");
			                }
                        }
                    }

                }
                pw.close();
            }
            catch (IOException e)
            {
                throw new RuntimeException(e);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

}
